home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / hop.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  11KB  |  439 lines

  1. /*
  2.  *    HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  *    08-90    -- Modified by Bill Simpson to display domain names
  9.  *
  10.  *  Mods by PA0GRI  (newsession param)
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "usock.h"
  18. #include "socket.h"
  19. #include "session.h"
  20. #include "timer.h"
  21. #include "proc.h"
  22. #include "netuser.h"
  23. #include "domain.h"
  24. #include "commands.h"
  25. #include "tty.h"
  26. #include "cmdparse.h"
  27. #include "ip.h"
  28. #include "icmp.h"
  29. #include "udp.h"
  30. #include "hardware.h"
  31.  
  32. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  33. static int16 Hoprport = 32768+666;    /* funny port for udp probes */
  34. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  35.  
  36.  
  37. #define HOPTRACE    1        /* Enable HOP tracing */
  38. #ifdef HOPTRACE
  39. static int Hoptrace = 0;
  40. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  41. #endif
  42.  
  43.  
  44. static unsigned  short Hopmaxttl  = 30;        /* max attempts */
  45. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  46. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  47.  
  48. static int hopcheck __ARGS((int argc,char *argv[],void *p));
  49. static int hopttl __ARGS((int argc,char *argv[],void *p));
  50. static int hopwait __ARGS((int argc,char *argv[],void *p));
  51. static int hopnum __ARGS((int argc,char *argv[],void *p));
  52. static int geticmp __ARGS((int s,int16 lport,int16 fport,
  53.     int32 *sender,char *type,char *code));
  54.  
  55. static struct cmds Hopcmds[] = {
  56.     "check",    hopcheck,    2048,    2,    "check <host>",
  57.     "maxttl",    hopttl,        0,    0,    NULLCHAR,
  58.     "maxwait",    hopwait,    0,    0,    NULLCHAR,
  59.     "queries",    hopnum,        0,    0,    NULLCHAR,
  60. #ifdef HOPTRACE
  61.     "trace",    hoptrace,    0,    0,    NULLCHAR,
  62. #endif
  63.     NULLCHAR,
  64. };
  65.  
  66. /* attempt to trace route to a remote host */
  67. int
  68. dohop(argc,argv,p)
  69. int argc;
  70. char *argv[];
  71. void *p;
  72. {
  73.     return subcmd(Hopcmds,argc,argv,p);
  74. }
  75.  
  76. /* Set/show # queries sent each TTL value */
  77. static int
  78. hopnum(argc,argv,p)
  79. int argc;
  80. char *argv[];
  81. void *p;
  82. {
  83.     int16 r;
  84.     int16 x = Hopquery;
  85.     r = setshort(&x,"# queries each attempt",argc,argv);
  86.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  87.         tprintf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  88.         return 0;
  89.     } else {
  90.         Hopquery = x;
  91.     }
  92.     return (int)r;
  93. }
  94. #ifdef HOPTRACE
  95. /* Set/show tracelevel */
  96. static int
  97. hoptrace(argc,argv,p)
  98. int argc;
  99. char *argv[];
  100. void *p;
  101. {
  102.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  103. }
  104. #endif
  105. /* Set/show maximum TTL value for a hopcheck query */
  106. static int
  107. hopttl(argc,argv,p)
  108. int argc;
  109. char *argv[];
  110. void *p;
  111. {
  112.     int16 r;
  113.     int16 x = Hopmaxttl;
  114.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  115.     if ((x <= 0)||(x > 255)) {
  116.         tprintf("Must be  0 < x <= 255\n");
  117.         return 0;
  118.     } else {
  119.         Hopmaxttl = x;
  120.     }
  121.     return (int)r;
  122. }
  123. /* Set/show #secs until timeout for a hopcheck query */
  124. static int
  125. hopwait(argc,argv,p)
  126. int argc;
  127. char *argv[];
  128. void *p;
  129. {
  130.     int16 r;
  131.     int16 x = Hopmaxwait;
  132.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  133.     if (x <= 0) {
  134.         tprintf("Must be >= 0\n");
  135.         return 0;
  136.     } else {
  137.         Hopmaxwait = x;
  138.     }
  139.     return (int)r;
  140. }
  141.  
  142. /* send probes to trace route of a remote host */
  143. static int
  144. hopcheck(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149.     struct session *sp;        /* Session for trace output */
  150.     int s;                /* Socket for queries */
  151.     int s1;                /* Raw socket for replies */
  152.     struct socket lsocket;        /* Local socket sending queries */
  153.     struct socket rsocket;        /* Final destination of queries */
  154.     int32 cticks;            /* Timer for query replies */
  155.     int32 icsource;            /* Sender of last ICMP reply */
  156.     char ictype;            /* ICMP type last ICMP reply */
  157.     char iccode;            /* ICMP code last ICMP reply */
  158.     int32 lastaddr;            /* Sender of previous ICMP reply */
  159.     struct sockaddr_in sock;
  160.     register struct usock *usp;
  161.     register struct sockaddr_in *sinp;
  162.     unsigned char sndttl, q;
  163.     int tracedone = 0;
  164.     int ilookup = 1;        /* Control of inverse domain lookup */
  165.     int c;
  166.     extern int optind;
  167.     char *hostname;
  168. #ifdef g1emmx
  169.     char *sname;            /* Used in resolve_a() call */
  170. #endif
  171.     int trans;            /* Save IP address translation state */
  172.     int save_trace;
  173.  
  174.     /*Make sure this comes from console - WG7J*/
  175.     if(Curproc->input != Command->input)
  176.         return 0;
  177.  
  178.     optind = 1;
  179.     while((c = getopt(argc,argv,"n")) != EOF){
  180.         switch(c){
  181.         case 'n':
  182.             ilookup = 0;
  183.             break;
  184.         }
  185.     }
  186.     hostname = argv[optind];
  187.     /* Allocate a session descriptor */
  188.     if((sp = newsession(hostname,HOP,0)) == NULLSESSION){
  189.         tputs(TooManySessions);
  190.         keywait(NULLCHAR,1);
  191.         return 1;
  192.     }
  193.     sp->s = s = -1;
  194.     sp->flowmode = 1;
  195.  
  196.     /* Setup UDP socket to remote host */
  197.     sock.sin_family = AF_INET;
  198.     sock.sin_port = Hoprport;
  199.     tprintf("Resolving %s... ",hostname);
  200.     if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  201.         tprintf(Badhost,hostname);
  202.         keywait(NULLCHAR,1);
  203.         freesession(sp);
  204.         return 1;
  205.     }
  206.  
  207.     /* Open socket to remote host */
  208.     tprintf("hopcheck to %s\n",psocket((struct sockaddr *)&sock));
  209.     if((sp->s = s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  210.         tputs(Nosock);
  211.         keywait(NULLCHAR,1);
  212.         freesession(sp);
  213.         return 1;
  214.     }
  215.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  216.         tprintf("Connect failed\n");
  217.         keywait(NULLCHAR,1);
  218.         freesession(sp);
  219.         return 1;
  220.     }
  221.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  222.         tputs(Nosock);
  223.         keywait(NULLCHAR,1);
  224.         freesession(sp);
  225.         return 1;
  226.     }
  227.     /* turn off icmp tracing while hop-checking */
  228.     save_trace = Icmp_trace;
  229.     Icmp_trace = 0;
  230.     /* Setup structures to send queries */
  231.     /* Retrieve socket details for user socket control block */
  232.     usp = itop(s);
  233.     sinp = (struct sockaddr_in *)usp->name;
  234.     lsocket.address = sinp->sin_addr.s_addr;
  235.     lsocket.port = sinp->sin_port;
  236.     sinp = (struct sockaddr_in *)usp->peername;
  237.     rsocket.address = sinp->sin_addr.s_addr;
  238.  
  239.     /* Send queries with increasing TTL; start with TTL=1 */
  240.     if (Hoptrace)
  241.         log(sp->s,"HOPCHECK start trace to %s\n",sp->name);
  242.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  243.         /* Increment funny UDP port number each round */
  244.         rsocket.port = sinp->sin_port;
  245.         tprintf("%3d:",sndttl);
  246.         lastaddr = (int32)0;
  247.         /* Send a round of queries */
  248.         for (q=0; (q < Hopquery); ++q) {
  249.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  250.             cticks = msclock();
  251.             alarm( ((long)Hopmaxwait*1000L) );
  252.  
  253.             /* Wait for a reply to our query */
  254.             if(geticmp(s1,lsocket.port,rsocket.port,
  255.              &icsource,&ictype,&iccode) == -1){
  256.                 if(errno != EALARM){
  257.                     alarm((long)0);    /* cancel alarm */
  258.                     goto done;    /* User reset */
  259.                 }
  260.                 /* Alarm rang, give up waiting for replies */
  261.                 tprintf(" ***");
  262.                 continue;
  263.             }
  264.             /* Save #ticks taken for reply */
  265.             cticks = msclock() - cticks;
  266.             /* Report ICMP reply */
  267.             if (icsource != lastaddr) {
  268.                 struct rr *save_rrlp, *rrlp;
  269.  
  270.                 if(lastaddr != (int32)0)
  271.                     tprintf("\n    ");
  272.             /* Save IP address translation state */
  273.                 trans = DTranslate;
  274.             /* Force output to be numeric IP addr */
  275.                 DTranslate = 0;
  276.                 tprintf(" %-15s",inet_ntoa(icsource));
  277.             /* Restore original state */
  278.                 DTranslate = trans;
  279. #ifdef g1emmx
  280.                 if((sname = resolve_a(icsource, FALSE)) != NULLCHAR) {
  281.                     tprintf(" %s", sname);
  282.                     free(sname);
  283.                 }
  284. #else
  285.                 if(ilookup){
  286.                     for(rrlp = save_rrlp = inverse_a(icsource);
  287.                         rrlp != NULLRR;
  288.                         rrlp = rrlp->next){
  289.                         if(rrlp->rdlength > 0){
  290.                             switch(rrlp->type){
  291.                             case TYPE_PTR:
  292.                                 tprintf(" %s", rrlp->rdata.name);
  293.                                 break;
  294.                             case TYPE_A:
  295.                                 tprintf(" %s", rrlp->name);
  296.                                 break;
  297.                             }
  298.                             if(rrlp->next != NULLRR)
  299.                                 tprintf("\n%20s"," ");
  300.                         }
  301.                     }
  302.                     free_rr(save_rrlp);
  303. #endif
  304.                 }
  305.                 lastaddr = icsource;
  306.             }
  307.             tprintf(" (%ld ms)",cticks);
  308. #ifdef HOPTRACE
  309.             if (Hoptrace)
  310.                 log(sp->s,
  311.                     "(hopcheck) ICMP from %s (%ldms) %s %s",
  312.                     inet_ntoa(icsource),
  313.                     cticks,
  314.                     Icmptypes[ictype],
  315.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  316. #endif
  317.  
  318.             /* Check type of reply */
  319.             if (ictype == ICMP_TIME_EXCEED)
  320.                 continue;
  321.             /* Reply was: destination unreachable */
  322.             switch(iccode) {
  323.             case ICMP_PORT_UNREACH:
  324.                 ++tracedone;
  325.                 break;
  326.             case ICMP_NET_UNREACH:
  327.                 ++tracedone;
  328.                 tprintf(" !N");
  329.                 break;
  330.             case ICMP_HOST_UNREACH:
  331.                 ++tracedone;
  332.                 tprintf(" !H");
  333.                 break;
  334.             case ICMP_PROT_UNREACH:
  335.                 ++tracedone;
  336.                 tprintf(" !P");
  337.                 break;
  338.             case ICMP_FRAG_NEEDED:
  339.                 ++tracedone;
  340.                 tprintf(" !F");
  341.                 break;
  342.             case ICMP_ROUTE_FAIL:
  343.                 ++tracedone;
  344.                 tprintf(" !S");
  345.                 break;
  346.             case ICMP_ADMIN_PROHIB:
  347.                 ++tracedone;
  348.                 tprintf(" !A");
  349.                 break;
  350.             default:
  351.                 tprintf(" !?");
  352.                 break;
  353.             }
  354.         }
  355.         /* Done with this round of queries */
  356.         alarm((long)0);
  357.         tprintf("\n");
  358.         /* Check if we reached remote host this round */
  359.         if (tracedone != 0)
  360.             break;
  361.     }
  362.  
  363.     /* Done with hopcheck */
  364. done:    close_s(s);
  365.     sp->s = -1;
  366.     close_s(s1);
  367.     tprintf("hopcheck done: ");
  368.     Icmp_trace = save_trace;
  369.     if (sndttl >= Hopmaxttl) {
  370.         tprintf("!! maximum TTL exceeded\n");
  371.     } else if ((icsource == rsocket.address)
  372.             &&(iccode == ICMP_PORT_UNREACH)) {
  373.         tprintf("normal (%s %s)\n",
  374.             Icmptypes[ictype],Unreach[iccode]);
  375.     } else {
  376.         tprintf("!! %s %s\n",
  377.             Icmptypes[ictype],Unreach[iccode]);
  378.     }
  379. #ifdef HOPTRACE
  380.     if (Hoptrace)
  381.         log(sp->s,"HOPCHECK to %s done",sp->name);
  382. #endif
  383.     keywait(NULLCHAR,1);
  384.     freesession(sp);
  385.     return 0;
  386. }
  387.  
  388. /* Read raw network socket looking for ICMP messages in response to our
  389.  * UDP probes
  390.  */
  391. static int
  392. geticmp(s,lport,fport,sender,type,code)
  393. int s;
  394. int16 lport;
  395. int16 fport;
  396. int32 *sender;
  397. char *type,*code;
  398. {
  399.     int size;
  400.     struct icmp icmphdr;
  401.     struct ip iphdr;
  402.     struct udp udphdr;
  403.     struct mbuf *bp;
  404.     struct sockaddr_in sock;
  405.  
  406.     for(;;){
  407.         size = sizeof(sock);
  408.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  409.             return -1;
  410.         /* It's an ICMP message, let's see if it's interesting */
  411.         ntohicmp(&icmphdr,&bp);
  412.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  413.          icmphdr.code != ICMP_TTL_EXCEED)
  414.          && icmphdr.type != ICMP_DEST_UNREACH){
  415.             /* We're not interested in these */
  416.             free_p(bp);
  417.             continue;
  418.         }
  419.         ntohip(&iphdr,&bp);
  420.         if(iphdr.protocol != UDP_PTCL){
  421.             /* Not UDP, so can't be interesting */
  422.             free_p(bp);
  423.             continue;
  424.         }
  425.         ntohudp(&udphdr,&bp);
  426.         if(udphdr.dest != fport || udphdr.source != lport){
  427.             /* Not from our hopcheck session */
  428.             free_p(bp);
  429.             continue;
  430.         }
  431.         /* Passed all of our checks, so return it */
  432.         *sender = sock.sin_addr.s_addr;
  433.         *type = icmphdr.type;
  434.         *code = icmphdr.code;
  435.         free_p(bp);
  436.         return 0;
  437.     }
  438. }
  439.